﻿using System;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using PhoenixCrabV6.Engine.IO;
using PhoenixCrabV6.Engine.Screens;

namespace PhoenixCrabV6.Engine.Images
{
    [DataContract]
    [KnownType(typeof (MultiImage))]
    [KnownType(typeof (TextImage))]
    public class Image : IImage
    {
        /// <summary>
        /// The rendered display image
        /// </summary>
        [XmlIgnore]
        public virtual Texture2D DisplayImage
        {
            get { return displayImage; }
            set
            {
                SourceImage = value;
                displayImage = SourceImage;
                dimensions = CalculateDimensions();

                if (CropRange == Rectangle.Empty)
                    CropRange = new Rectangle(0, 0, (int) dimensions.X, (int) dimensions.Y);

                //todo check this out - throws out of memory exception
                if (renderTarget == null)
                    renderTarget = new RenderTarget2D(ScreenManager.Instance.GraphicsDevice, (int) dimensions.X,
                        (int) dimensions.Y);
            }
        }

        private Texture2D displayImage;

        /// <summary>
        /// Path to the source image
        /// </summary>
        [DataMember]
        public virtual string Path { get; set; }

        /// <summary>
        /// Alpha value override
        /// </summary>
        [DataMember]
        public float Alpha { get; set; }

        /// <summary>
        /// Positioning & Scaling information
        /// </summary>
        [DataMember]
        public Vector2 Position { get; set; }

        /// <summary>
        /// Positioning & Scaling information
        /// </summary>
        [DataMember]
        public Vector2 Scale { get; set; }

        /// <summary>
        /// Draw what is inside the bounds defined by rectangle - null draws all
        /// </summary>
        [DataMember]
        public Rectangle CropRange { get; set; }

        protected Texture2D SourceImage;

        protected Vector2 origin;

        protected ContentManager content;

        protected RenderTarget2D renderTarget;

        protected Vector2 dimensions;

        public Image()
        {
            Path = string.Empty;
            Initialize();
        }

        public Image(string path)
        {
            Path = path;
            Initialize();
        }

        public Image(Texture2D image)
        {
            SourceImage = image;
            Initialize();

            dimensions = CalculateDimensions();

            if (CropRange == Rectangle.Empty)
                CropRange = new Rectangle(0, 0, (int) dimensions.X, (int) dimensions.Y);
            renderTarget = new RenderTarget2D(ScreenManager.Instance.GraphicsDevice, (int) dimensions.X,
                (int) dimensions.Y);

            DisplayImage = SourceImage;
        }

        protected virtual void Initialize()
        {
            /*** Default definitions ***/

            Position = Vector2.Zero;
            Scale = Vector2.One;
            Alpha = 1.0f;
            CropRange = Rectangle.Empty;
        }

        public virtual void LoadContent()
        {
            content = new ContentManager(ScreenManager.Instance.Content.ServiceProvider, "Content");

            if (Path != String.Empty)
                SourceImage = content.Load<Texture2D>(Path);
            else
                throw new XMLLoadException("Image not defined");


            dimensions = CalculateDimensions();

            if (CropRange == Rectangle.Empty)
                CropRange = new Rectangle(0, 0, (int) dimensions.X, (int) dimensions.Y);
            renderTarget = new RenderTarget2D(ScreenManager.Instance.GraphicsDevice, (int) dimensions.X,
                (int) dimensions.Y);

            ScreenManager.Instance.GraphicsDevice.SetRenderTarget(renderTarget);
            ScreenManager.Instance.GraphicsDevice.Clear(Color.Transparent);
            ScreenManager.Instance.SpriteBatch.Begin();

            if (SourceImage != null)
                ScreenManager.Instance.SpriteBatch.Draw(SourceImage, Vector2.Zero, Color.White);

            ScreenManager.Instance.SpriteBatch.End();

            //We are rendering this image to a texture, instead of a screen.
            displayImage = renderTarget;
            ScreenManager.Instance.GraphicsDevice.SetRenderTarget(null);
        }

        public void UnloadContent()
        {
            content.Unload();
        }

        public void Update(GameTime gameTime)
        {
            /*** Effects Update ***/
            //if (FadeEffect != null) FadeEffect.Update(gameTime);
        }

        /// <summary>
        /// Draws the image with the upper left corner as the reference point
        /// </summary>
        /// <param name="spriteBatch"></param>
        public virtual void Draw(SpriteBatch spriteBatch)
        {
            origin = new Vector2(CropRange.Width/2, CropRange.Height/2);

            //todo does displayimage change according to what designated to draw?
            spriteBatch.Draw(DisplayImage, (Position + origin), CropRange, Color.White*Alpha, 0.0f, origin, Scale,
                SpriteEffects.None,
                0.0f);
        }

        private Vector2 CalculateDimensions()
        {
            Vector2 v = Vector2.Zero;

            if (SourceImage != null)
            {
                v.X += SourceImage.Width;
                v.Y = SourceImage.Height;
            }

            return v;
        }
    }
}